/**
 * 中文URL封装 (zh-url.js)
 * 支持URL操作、参数解析与生成、链式调用
 * 中文方法命名 + JSDoc 参数提示
 */

class URL操作 {
  /**
   * 构造函数 - 创建URL操作实例
   * @param {string} url URL字符串，默认为空字符串
   */
  constructor(url = '') {
    this._url = new URL(url, window.location.origin);
  }

  /**
   * 获取原始URL对象
   * @returns {URL} 原生URL对象
   */
  取值() {
    return this._url;
  }

  /**
   * 获取完整URL字符串
   * @returns {string} 完整的URL字符串
   */
  转字符串() {
    return this._url.toString();
  }

  /**
   * 获取完整URL路径
   * @returns {string} 完整的URL路径(href)
   */
  获取完整路径() {
    return this._url.href;
  }

  /**
   * 获取URL协议
   * @returns {string} 协议部分（如 'http:'、'https:'）
   */
  获取协议() {
    return this._url.protocol;
  }

  /**
   * 设置URL协议
   * @param {string} 协议 协议字符串（如 'http:'、'https:'）
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置协议(协议) {
    this._url.protocol = 协议;
    return this;
  }

  /**
   * 获取主机名
   * @returns {string} 主机名部分（如 example.com）
   */
  获取主机名() {
    return this._url.hostname;
  }

  /**
   * 设置主机名
   * @param {string} 主机名 主机名字符串
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置主机名(主机名) {
    this._url.hostname = 主机名;
    return this;
  }

  /**
   * 获取端口号
   * @returns {string} 端口号字符串
   */
  获取端口() {
    return this._url.port;
  }

  /**
   * 设置端口号
   * @param {string|number} 端口 端口号
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置端口(端口) {
    this._url.port = 端口;
    return this;
  }

  /**
   * 获取路径名
   * @returns {string} 路径名部分（如'/path/to/resource'）
   */
  获取路径名() {
    return this._url.pathname;
  }

  /**
   * 设置路径名
   * @param {string} 路径名 路径名字符串
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置路径名(路径名) {
    this._url.pathname = 路径名;
    return this;
  }

  /**
   * 获取查询字符串
   * @returns {string} 查询字符串部分（包含?前缀，如 '?key=value'）
   */
  获取查询字符串() {
    return this._url.search;
  }

  /**
   * 设置查询字符串
   * @param {string} 查询字符串 查询字符串（可以包含或不包含'?'）
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置查询字符串(查询字符串) {
    this._url.search = 查询字符串;
    return this;
  }

  /**
   * 解析查询参数为对象
   * @returns {Object<string, string>} 解析后的参数键值对对象
   */
  解析参数() {
    const 参数 = {};
    for (const [键, 值] of this._url.searchParams) {
      参数[键] = 值;
    }
    return 参数;
  }

  /**
   * 根据对象生成查询参数
   * @param {Object<string, string|number>} 参数对象 包含键值对的参数对象
   * @returns {URL操作} 返回this以支持链式调用
   */
  生成参数(参数对象) {
    const 查询参数 = new URLSearchParams();
    for (const [键, 值] of Object.entries(参数对象)) {
      查询参数.set(键, 值);
    }
    this._url.search = 查询参数.toString();
    return this;
  }

  /**
   * 添加单个查询参数
   * @param {string} 键 参数名
   * @param {string|number} 值 参数值
   * @returns {URL操作} 返回this以支持链式调用
   */
  添加参数(键, 值) {
    this._url.searchParams.set(键, 值);
    return this;
  }

  /**
   * 批量添加查询参数
   * @param {Object<string, string|number>} 参数对象 包含多个键值对的参数对象
   * @returns {URL操作} 返回this以支持链式调用
   */
  添加多个参数(参数对象) {
    for (const [键, 值] of Object.entries(参数对象)) {
      this._url.searchParams.set(键, 值);
    }
    return this;
  }

  /**
   * 获取指定参数的值
   * @param {string} 键 参数名
   * @returns {string|null} 参数值，如果不存在则返回null
   */
  获取参数(键) {
    return this._url.searchParams.get(键);
  }

  /**
   * 获取指定参数的所有值（适用于多值参数）
   * @param {string} 键 参数名
   * @returns {string[]} 参数值数组
   */
  获取参数所有值(键) {
    return this._url.searchParams.getAll(键);
  }

  /**
   * 删除指定参数
   * @param {string} 键 参数名
   * @returns {URL操作} 返回this以支持链式调用
   */
  删除参数(键) {
    this._url.searchParams.delete(键);
    return this;
  }

  /**
   * 批量删除参数
   * @param {...string} 键列表 要删除的参数名列表
   * @returns {URL操作} 返回this以支持链式调用
   */
  删除多个参数(...键列表) {
    for (const 键 of 键列表) {
      this._url.searchParams.delete(键);
    }
    return this;
  }

  /**
   * 检查是否包含指定参数
   * @param {string} 键 参数名
   * @returns {boolean} 是否包含该参数
   */
  包含参数(键) {
    return this._url.searchParams.has(键);
  }

  /**
   * 获取URL锚点
   * @returns {string} 锚点部分（包含#前缀，如 '#section1'）
   */
  获取锚点() {
    return this._url.hash;
  }

  /**
   * 设置URL锚点
   * @param {string} 锚点 锚点字符串（可以包含或不包含 '#'）
   * @returns {URL操作} 返回this以支持链式调用
   */
  设置锚点(锚点) {
    this._url.hash = 锚点;
    return this;
  }

  /**
   * 比较URL是否相等
   * @param {string|URL} 其他URL 要比较的URL
   * @returns {boolean} 是否相等
   */
  是否相等(其他URL) {
    const 其他 = 其他URL instanceof URL ? 其他URL : new URL(其他URL, window.location.origin);
    return this._url.toString() === 其他.toString();
  }

  /**
   * 创建URL操作实例的副本
   * @returns {URL操作} 新的URL操作实例
   */
  克隆() {
    return new URL操作(this._url.toString());
  }

  /** 静态方法 */

  /**
   * 静态方法：解析查询字符串为对象
   * @static
   * @param {string} 查询字符串 查询字符串（可以包含或不包含 '?'）
   * @returns {Object<string, string>} 解析后的参数键值对对象
   */
  static 解析查询字符串(查询字符串) {
    const 参数 = {};
    const 搜索参数 = new URLSearchParams(查询字符串);
    for (const [键, 值] of 搜索参数) {
      参数[键] = 值;
    }
    return 参数;
  }

  /**
   * 静态方法：将对象转换为查询字符串
   * @static
   * @param {Object<string, string|number>} 参数对象 包含键值对的参数对象
   * @returns {string} 转换后的查询字符串（不包含 '?'）
   */
  static 对象转查询字符串(参数对象) {
    const 搜索参数 = new URLSearchParams();
    for (const [键, 值] of Object.entries(参数对象)) {
      搜索参数.set(键, 值);
    }
    return 搜索参数.toString();
  }

  /**
   * 静态方法：编码URL
   * @static
   * @param {string} url 要编码的URL
   * @returns {string} 编码后的URL
   */
  static 编码(url) {
    return encodeURI(url);
  }

  /**
   * 静态方法：解码URL
   * @static
   * @param {string} url 要解码的URL
   * @returns {string} 解码后的URL
   */
  static 解码(url) {
    return decodeURI(url);
  }

  /**
   * 静态方法：编码URL组件
   * @static
   * @param {string} 组件 要编码的URL组件
   * @returns {string} 编码后的组件
   */
  static 编码组件(组件) {
    return encodeURIComponent(组件);
  }

  /**
   * 静态方法：解码URL组件
   * @static
   * @param {string} 组件 要解码的URL组件
   * @returns {string} 解码后的组件
   */
  static 解码组件(组件) {
    return decodeURIComponent(组件);
  }

  /**
   * 静态方法：合并URL路径
   * @static
   * @param {string} 基础路径 基础URL路径
   * @param {string} 相对路径 相对路径
   * @returns {string} 合并后的完整路径
   */
  static 合并路径(基础路径, 相对路径) {
    // 移除基础路径末尾的斜杠和相对路径开头的斜杠
    const 处理后的基础路径 = 基础路径.replace(/\/$/, '');
    const 处理后的相对路径 = 相对路径.replace(/^\//, '');
    return `${处理后的基础路径}/${处理后的相对路径}`;
  }
}

// 规范导出
export { URL操作 };
export default URL操作;